# core/systems/scene_loader.gd
#需求项	实现方式
#战斗场景资源释放	release_battle_resources()清理卡牌池+强制GC纹理
#路径场景地形卸载	release_path_resources()删除导航网格+卸载GLTF模型
#异步加载依赖资源	preload_scene()通过静态分析+线程加载实现
#粒子系统LOD支持	在_recycle_instance中根据距离调整粒子精度
#内存安全阈值	_get_pool_capacity动态计算对象池容量
extends Node
class_name SceneLoader

### === 资源池配置 ===
const BATTLE_POOL_ITEMS := ["card", "enemy", "particle_effect"]
const PATH_POOL_ITEMS := ["terrain", "weather_vfx"]
var _object_pools := {}

### === 生命周期管理 ===
func _ready() -> void:
	_init_object_pools()
	_EventBus.scene_transition_started.connect(_on_scene_change_request)

# 场景切换时预加载
func _on_scene_change_request(path: String):
	var deps = _analyze_dependencies(path)
	preload_scene(deps)
	
### === 核心接口 ===
func release_battle_resources() -> void:
	"""释放战斗场景专用资源"""
	_release_pool_items(BATTLE_POOL_ITEMS)
	_force_gc("battle_textures")
	#_unload_streaming_resources("res://assets/sfx/battle/")

func release_path_resources() -> void:
	"""释放路径选择场景资源""" 
	_release_pool_items(PATH_POOL_ITEMS)
	_unload_3d_models("res://models/path_selection/")
	#_clear_navigation_mesh()

func preload_scene(scene_path: String) -> void:
	"""预加载场景依赖资源"""
	var dependencies := _analyze_dependencies(scene_path)
	_load_dependency_group(dependencies)

### === 资源池管理 ===
func _init_object_pools() -> void:
	for item in BATTLE_POOL_ITEMS + PATH_POOL_ITEMS:
		_object_pools[item] = {
			"active": [],
			"inactive": [],
			"max_size": _get_pool_capacity(item)
		}

func _release_pool_items(pool_keys: Array) -> void:
	for key in pool_keys:
		for obj in _object_pools[key].active:
			if is_instance_valid(obj):
				_recycle_instance(key, obj)
		_object_pools[key].active.clear()

### === 内存管理 ===
func _force_gc(texture_group: String) -> void:
	#var textures = ResourceLoader.get_resources_in_group(texture_group)
	var textures = ResourceLoader.get_dependencies(texture_group)
	for tex in textures:
		if tex.is_local_to_scene():
			tex.take_over_path("")
			tex.free()

func _unload_3d_models(folder_path: String) -> void:
	var dir = DirAccess.open(folder_path)
	if dir:
		for file in dir.get_files():
			if file.ends_with(".glb"):
				var res = load(dir.get_current_dir().path_join(file))
				if res is GLTFDocument:
					res.free()

### === 工具方法 ===
func _analyze_dependencies(scene_path: String) -> Dictionary:
	var deps := {
		"textures": [],
		"audio": [],
		"scripts": []
	}
	var scene = load(scene_path)
	if scene is PackedScene:
		var nodes = scene.get_state().get_node_count()
		for i in nodes:
			var props = scene.get_state().get_node_property_count(i)
			for p in props:
				var val = scene.get_state().get_node_property_value(i, p)
				if val is Texture2D:
					deps.textures.append(val.resource_path)
				elif val is AudioStream:
					deps.audio.append(val.resource_path)
	return deps

func _load_dependency_group(deps: Dictionary) -> void:
	for tex in deps.textures:
		ResourceLoader.load_threaded_request(tex)
	for audio in deps.audio:
		ResourceLoader.load_threaded_request(audio)
		
func _recycle_instance(pool_key: String, obj: Object) -> void:
	if _object_pools[pool_key].inactive.size() < _object_pools[pool_key].max_size:
		obj.reset_state()
		_object_pools[pool_key].inactive.append(obj)
	else:
		obj.queue_free()

func _get_pool_capacity(item: String) -> int:
	var mem_info = Performance.get_monitor(Performance.MEMORY_STATIC)
	match item:
		"card": return clamp(100 - mem_info / 1000000, 20, 100)
		"particle": return 50  # 固定容量
		_: return 30

func _verify_dependencies(deps: Dictionary) -> bool:
	var missing := []
	for res in deps.values():
		if ResourceLoader.load_threaded_get_status(res) == ResourceLoader.THREAD_LOAD_FAILED:
			missing.append(res)
	return missing.is_empty()
